// RouteRecommendationReducer.java
package com.taxi.analysis.recommendation;

import java.io.IOException;
import java.util.*;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

/**
 * 路线推荐系统Reducer
 * 功能：基于自定义分组数据生成路线推荐
 * 技术：自定义分组 + 推荐算法
 */
public class RouteRecommendationReducer extends Reducer<Text, Text, Text, Text> {

    @Override
    public void reduce(Text key, Iterable<Text> values, Context context)
            throws IOException, InterruptedException {

        String groupKey = key.toString();
        String[] keyParts = groupKey.split("_", 2);

        if (keyParts.length >= 2) {
            String groupType = keyParts[0];
            String groupId = keyParts[1];

            switch (groupType) {
                case "USER":
                    processUserBehavior(groupId, values, context);
                    break;
                case "ROUTE":
                    processRouteAnalysis(groupId, values, context);
                    break;
                case "TIME":
                    processTimePattern(groupId, values, context);
                    break;
                case "PICKUP":
                    processPickupSimilarity(groupId, values, context);
                    break;
            }
        }
    }

    /**
     * 处理用户行为分析
     */
    private void processUserBehavior(String userId, Iterable<Text> values, Context context)
            throws IOException, InterruptedException {

        List<UserTrip> userTrips = new ArrayList<>();

        // 解析用户行程数据
        for (Text value : values) {
            try {
                String record = value.toString();
                if (record.startsWith("USER_BEHAVIOR|")) {
                    String data = record.substring("USER_BEHAVIOR|".length());
                    UserTrip trip = parseUserTrip(data);
                    if (trip != null) {
                        userTrips.add(trip);
                    }
                }
            } catch (Exception e) {
                System.err.println("解析用户行程错误: " + value.toString());
            }
        }

        if (!userTrips.isEmpty()) {
            // 分析用户偏好
            UserPreference preference = analyzeUserPreference(userTrips);

            // 生成个性化推荐
            List<RouteRecommendation> recommendations = generatePersonalizedRecommendations(preference, userTrips);

            // 输出用户偏好分析
            outputUserPreference(userId, preference, context);

            // 输出推荐结果
            outputUserRecommendations(userId, recommendations, context);
        }
    }

    /**
     * 处理路线分析
     */
    private void processRouteAnalysis(String routeId, Iterable<Text> values, Context context)
            throws IOException, InterruptedException {

        List<RouteUsage> routeUsages = new ArrayList<>();

        // 解析路线使用数据
        for (Text value : values) {
            try {
                String record = value.toString();
                if (record.startsWith("ROUTE_ANALYSIS|")) {
                    String data = record.substring("ROUTE_ANALYSIS|".length());
                    RouteUsage usage = parseRouteUsage(data);
                    if (usage != null) {
                        routeUsages.add(usage);
                    }
                }
            } catch (Exception e) {
                System.err.println("解析路线使用错误: " + value.toString());
            }
        }

        if (!routeUsages.isEmpty()) {
            // 分析路线特征
            RouteCharacteristics characteristics = analyzeRouteCharacteristics(routeUsages);

            // 输出路线分析结果
            outputRouteAnalysis(routeId, characteristics, context);
        }
    }

    /**
     * 处理时间模式分析
     */
    private void processTimePattern(String timeKey, Iterable<Text> values, Context context)
            throws IOException, InterruptedException {

        List<TimeTrip> timeTrips = new ArrayList<>();

        // 解析时间段行程数据
        for (Text value : values) {
            try {
                String record = value.toString();
                if (record.startsWith("TIME_PATTERN|")) {
                    String data = record.substring("TIME_PATTERN|".length());
                    TimeTrip trip = parseTimeTrip(data);
                    if (trip != null) {
                        timeTrips.add(trip);
                    }
                }
            } catch (Exception e) {
                System.err.println("解析时间行程错误: " + value.toString());
            }
        }

        if (!timeTrips.isEmpty()) {
            // 分析时间段特征
            TimePatternAnalysis analysis = analyzeTimePattern(timeTrips);

            // 输出时间段分析结果
            outputTimePatternAnalysis(timeKey, analysis, context);
        }
    }

    /**
     * 处理起点相似性分析
     */
    private void processPickupSimilarity(String pickupLocation, Iterable<Text> values, Context context)
            throws IOException, InterruptedException {

        List<PickupTrip> pickupTrips = new ArrayList<>();

        // 解析起点行程数据
        for (Text value : values) {
            try {
                String record = value.toString();
                if (record.startsWith("PICKUP_SIMILARITY|")) {
                    String data = record.substring("PICKUP_SIMILARITY|".length());
                    PickupTrip trip = parsePickupTrip(data);
                    if (trip != null) {
                        pickupTrips.add(trip);
                    }
                }
            } catch (Exception e) {
                System.err.println("解析起点行程错误: " + value.toString());
            }
        }

        if (!pickupTrips.isEmpty()) {
            // 分析起点相似路线
            List<SimilarRoute> similarRoutes = analyzeSimilarRoutes(pickupTrips);

            // 输出相似路线推荐
            outputSimilarRoutes(pickupLocation, similarRoutes, context);
        }
    }

    /**
     * 分析用户偏好
     */
    private UserPreference analyzeUserPreference(List<UserTrip> trips) {
        UserPreference preference = new UserPreference();

        // 统计时间段偏好
        Map<String, Integer> timePeriodCounts = new HashMap<>();
        Map<String, Integer> dayTypeCounts = new HashMap<>();
        Map<String, Integer> qualityLevelCounts = new HashMap<>();

        double totalDistance = 0;
        double totalAmount = 0;
        double totalDuration = 0;
        int totalQualityScore = 0;

        for (UserTrip trip : trips) {
            timePeriodCounts.put(trip.timePeriod, timePeriodCounts.getOrDefault(trip.timePeriod, 0) + 1);
            dayTypeCounts.put(trip.dayType, dayTypeCounts.getOrDefault(trip.dayType, 0) + 1);
            qualityLevelCounts.put(trip.qualityLevel, qualityLevelCounts.getOrDefault(trip.qualityLevel, 0) + 1);

            totalDistance += trip.tripDistance;
            totalAmount += trip.totalAmount;
            totalDuration += trip.tripDuration;
            totalQualityScore += trip.qualityScore;
        }

        preference.totalTrips = trips.size();
        preference.avgDistance = totalDistance / trips.size();
        preference.avgAmount = totalAmount / trips.size();
        preference.avgDuration = totalDuration / trips.size();
        preference.avgQualityScore = (double) totalQualityScore / trips.size();

        preference.preferredTimePeriod = findMostFrequent(timePeriodCounts);
        preference.preferredDayType = findMostFrequent(dayTypeCounts);
        preference.preferredQualityLevel = findMostFrequent(qualityLevelCounts);

        return preference;
    }

    /**
     * 生成个性化推荐
     */
    private List<RouteRecommendation> generatePersonalizedRecommendations(UserPreference preference, List<UserTrip> trips) {
        List<RouteRecommendation> recommendations = new ArrayList<>();

        // 基于用户历史路线生成推荐
        Map<String, RouteStats> routeStatsMap = new HashMap<>();

        for (UserTrip trip : trips) {
            RouteStats stats = routeStatsMap.getOrDefault(trip.routeId, new RouteStats());
            stats.usageCount++;
            stats.totalAmount += trip.totalAmount;
            stats.totalDuration += trip.tripDuration;
            stats.totalQualityScore += trip.qualityScore;
            routeStatsMap.put(trip.routeId, stats);
        }

        // 计算推荐分数
        for (Map.Entry<String, RouteStats> entry : routeStatsMap.entrySet()) {
            String routeId = entry.getKey();
            RouteStats stats = entry.getValue();

            double recommendationScore = calculateRecommendationScore(stats, preference);

            if (recommendationScore > 0.5) { // 只推荐分数较高的路线
                RouteRecommendation rec = new RouteRecommendation();
                rec.routeId = routeId;
                rec.score = recommendationScore;
                rec.usageCount = stats.usageCount;
                rec.avgAmount = stats.totalAmount / stats.usageCount;
                rec.avgDuration = stats.totalDuration / stats.usageCount;
                rec.avgQualityScore = (double) stats.totalQualityScore / stats.usageCount;
                rec.reason = generateRecommendationReason(rec, preference);

                recommendations.add(rec);
            }
        }

        // 按推荐分数排序
        // 按推荐分数排序
        recommendations.sort((a, b) -> Double.compare(b.score, a.score));

        // 只返回前10个推荐
        return recommendations.subList(0, Math.min(10, recommendations.size()));
    }

    /**
     * 计算推荐分数
     */
    private double calculateRecommendationScore(RouteStats stats, UserPreference preference) {
        double score = 0.0;

        // 使用频率权重（30%）
        double usageWeight = Math.min(1.0, stats.usageCount / 10.0) * 0.3;
        score += usageWeight;

        // 质量分数权重（25%）
        double qualityWeight = (stats.totalQualityScore / stats.usageCount) / 10.0 * 0.25;
        score += qualityWeight;

        // 费用匹配权重（20%）
        double avgAmount = stats.totalAmount / stats.usageCount;
        double amountDiff = Math.abs(avgAmount - preference.avgAmount) / preference.avgAmount;
        double amountWeight = Math.max(0, 1.0 - amountDiff) * 0.2;
        score += amountWeight;

        // 时长匹配权重（15%）
        double avgDuration = stats.totalDuration / stats.usageCount;
        double durationDiff = Math.abs(avgDuration - preference.avgDuration) / preference.avgDuration;
        double durationWeight = Math.max(0, 1.0 - durationDiff) * 0.15;
        score += durationWeight;

        // 稳定性权重（10%）
        double stabilityWeight = Math.min(1.0, stats.usageCount / 5.0) * 0.1;
        score += stabilityWeight;

        return score;
    }

    /**
     * 生成推荐理由
     */
    private String generateRecommendationReason(RouteRecommendation rec, UserPreference preference) {
        List<String> reasons = new ArrayList<>();

        if (rec.usageCount >= 5) {
            reasons.add("常用路线");
        }
        if (rec.avgQualityScore >= 7) {
            reasons.add("高质量路线");
        }
        if (Math.abs(rec.avgAmount - preference.avgAmount) / preference.avgAmount <= 0.2) {
            reasons.add("费用匹配");
        }
        if (Math.abs(rec.avgDuration - preference.avgDuration) / preference.avgDuration <= 0.2) {
            reasons.add("时长合适");
        }

        return reasons.isEmpty() ? "综合推荐" : String.join(",", reasons);
    }

    /**
     * 分析路线特征
     */
    private RouteCharacteristics analyzeRouteCharacteristics(List<RouteUsage> usages) {
        RouteCharacteristics characteristics = new RouteCharacteristics();

        Map<String, Integer> timePeriodCounts = new HashMap<>();
        Map<String, Integer> dayTypeCounts = new HashMap<>();
        Set<String> uniqueUsers = new HashSet<>();

        double totalDistance = 0;
        double totalAmount = 0;
        double totalDuration = 0;
        int totalQualityScore = 0;

        for (RouteUsage usage : usages) {
            timePeriodCounts.put(usage.timePeriod, timePeriodCounts.getOrDefault(usage.timePeriod, 0) + 1);
            dayTypeCounts.put(usage.dayType, dayTypeCounts.getOrDefault(usage.dayType, 0) + 1);
            uniqueUsers.add(usage.userId);

            totalDistance += usage.tripDistance;
            totalAmount += usage.totalAmount;
            totalDuration += usage.tripDuration;
            totalQualityScore += usage.qualityScore;
        }

        characteristics.totalUsages = usages.size();
        characteristics.uniqueUsers = uniqueUsers.size();
        characteristics.avgDistance = totalDistance / usages.size();
        characteristics.avgAmount = totalAmount / usages.size();
        characteristics.avgDuration = totalDuration / usages.size();
        characteristics.avgQualityScore = (double) totalQualityScore / usages.size();
        characteristics.popularTimePeriod = findMostFrequent(timePeriodCounts);
        characteristics.popularDayType = findMostFrequent(dayTypeCounts);
        characteristics.userDiversity = (double) uniqueUsers.size() / usages.size();

        return characteristics;
    }

    /**
     * 分析时间模式
     */
    private TimePatternAnalysis analyzeTimePattern(List<TimeTrip> trips) {
        TimePatternAnalysis analysis = new TimePatternAnalysis();

        Map<String, Integer> routeCounts = new HashMap<>();
        Map<String, Integer> pickupCounts = new HashMap<>();
        Map<String, Integer> dropoffCounts = new HashMap<>();

        double totalDistance = 0;
        double totalAmount = 0;
        double totalDuration = 0;
        int totalQualityScore = 0;

        for (TimeTrip trip : trips) {
            routeCounts.put(trip.routeId, routeCounts.getOrDefault(trip.routeId, 0) + 1);
            pickupCounts.put(trip.pickupLocation, pickupCounts.getOrDefault(trip.pickupLocation, 0) + 1);
            dropoffCounts.put(trip.dropoffLocation, dropoffCounts.getOrDefault(trip.dropoffLocation, 0) + 1);

            totalDistance += trip.tripDistance;
            totalAmount += trip.totalAmount;
            totalDuration += trip.tripDuration;
            totalQualityScore += trip.qualityScore;
        }

        analysis.totalTrips = trips.size();
        analysis.avgDistance = totalDistance / trips.size();
        analysis.avgAmount = totalAmount / trips.size();
        analysis.avgDuration = totalDuration / trips.size();
        analysis.avgQualityScore = (double) totalQualityScore / trips.size();
        analysis.popularRoute = findMostFrequent(routeCounts);
        analysis.popularPickup = findMostFrequent(pickupCounts);
        analysis.popularDropoff = findMostFrequent(dropoffCounts);

        return analysis;
    }

    /**
     * 分析相似路线
     */
    private List<SimilarRoute> analyzeSimilarRoutes(List<PickupTrip> trips) {
        Map<String, SimilarRouteStats> routeStatsMap = new HashMap<>();

        for (PickupTrip trip : trips) {
            SimilarRouteStats stats = routeStatsMap.getOrDefault(trip.routeId, new SimilarRouteStats());
            stats.usageCount++;
            stats.totalAmount += trip.totalAmount;
            stats.totalDuration += trip.tripDuration;
            stats.totalDistance += trip.tripDistance;
            stats.totalQualityScore += trip.qualityScore;
            stats.dropoffLocation = trip.dropoffLocation;
            routeStatsMap.put(trip.routeId, stats);
        }

        List<SimilarRoute> similarRoutes = new ArrayList<>();
        for (Map.Entry<String, SimilarRouteStats> entry : routeStatsMap.entrySet()) {
            String routeId = entry.getKey();
            SimilarRouteStats stats = entry.getValue();

            if (stats.usageCount >= 3) { // 至少被使用3次才推荐
                SimilarRoute route = new SimilarRoute();
                route.routeId = routeId;
                route.dropoffLocation = stats.dropoffLocation;
                route.usageCount = stats.usageCount;
                route.avgAmount = stats.totalAmount / stats.usageCount;
                route.avgDuration = stats.totalDuration / stats.usageCount;
                route.avgDistance = stats.totalDistance / stats.usageCount;
                route.avgQualityScore = (double) stats.totalQualityScore / stats.usageCount;
                route.popularityScore = calculatePopularityScore(stats);

                similarRoutes.add(route);
            }
        }

        // 按热门程度排序
        similarRoutes.sort((a, b) -> Double.compare(b.popularityScore, a.popularityScore));

        return similarRoutes.subList(0, Math.min(15, similarRoutes.size()));
    }

    /**
     * 计算热门程度分数
     */
    private double calculatePopularityScore(SimilarRouteStats stats) {
        double usageScore = Math.min(1.0, stats.usageCount / 20.0) * 0.4;
        double qualityScore = (stats.totalQualityScore / stats.usageCount) / 10.0 * 0.3;
        double efficiencyScore = Math.min(1.0, (stats.totalDistance / stats.usageCount) / 20.0) * 0.3;

        return usageScore + qualityScore + efficiencyScore;
    }

    /**
     * 输出用户偏好分析
     */
    private void outputUserPreference(String userId, UserPreference preference, Context context)
            throws IOException, InterruptedException {

        String preferenceInfo = String.format("用户偏好|总行程:%d|平均距离:%.2f|平均费用:%.2f|平均时长:%.2f|平均质量:%.1f|偏好时段:%s|偏好日期:%s|偏好质量:%s",
                preference.totalTrips, preference.avgDistance, preference.avgAmount,
                preference.avgDuration, preference.avgQualityScore, preference.preferredTimePeriod,
                preference.preferredDayType, preference.preferredQualityLevel);

        context.write(new Text("用户偏好_" + userId), new Text(preferenceInfo));
    }

    /**
     * 输出用户推荐
     */
    private void outputUserRecommendations(String userId, List<RouteRecommendation> recommendations, Context context)
            throws IOException, InterruptedException {

        for (int i = 0; i < recommendations.size(); i++) {
            RouteRecommendation rec = recommendations.get(i);
            String recInfo = String.format("个性推荐|路线:%s|推荐分数:%.3f|使用次数:%d|平均费用:%.2f|平均时长:%.2f|平均质量:%.1f|推荐理由:%s",
                    rec.routeId, rec.score, rec.usageCount, rec.avgAmount,
                    rec.avgDuration, rec.avgQualityScore, rec.reason);

            context.write(new Text("个性推荐_" + userId + "_" + (i + 1)), new Text(recInfo));
        }
    }

    /**
     * 输出路线分析
     */
    private void outputRouteAnalysis(String routeId, RouteCharacteristics characteristics, Context context)
            throws IOException, InterruptedException {

        String analysisInfo = String.format("路线分析|总使用:%d|独立用户:%d|用户多样性:%.3f|平均距离:%.2f|平均费用:%.2f|平均时长:%.2f|平均质量:%.1f|热门时段:%s|热门日期:%s",
                characteristics.totalUsages, characteristics.uniqueUsers, characteristics.userDiversity,
                characteristics.avgDistance, characteristics.avgAmount, characteristics.avgDuration,
                characteristics.avgQualityScore, characteristics.popularTimePeriod, characteristics.popularDayType);

        context.write(new Text("路线分析_" + routeId), new Text(analysisInfo));
    }

    /**
     * 输出时间模式分析
     */
    private void outputTimePatternAnalysis(String timeKey, TimePatternAnalysis analysis, Context context)
            throws IOException, InterruptedException {

        String patternInfo = String.format("时间模式|总行程:%d|平均距离:%.2f|平均费用:%.2f|平均时长:%.2f|平均质量:%.1f|热门路线:%s|热门起点:%s|热门终点:%s",
                analysis.totalTrips, analysis.avgDistance, analysis.avgAmount,
                analysis.avgDuration, analysis.avgQualityScore, analysis.popularRoute,
                analysis.popularPickup, analysis.popularDropoff);

        context.write(new Text("时间模式_" + timeKey), new Text(patternInfo));
    }

    /**
     * 输出相似路线推荐
     */
    private void outputSimilarRoutes(String pickupLocation, List<SimilarRoute> similarRoutes, Context context)
            throws IOException, InterruptedException {

        for (int i = 0; i < Math.min(10, similarRoutes.size()); i++) {
            SimilarRoute route = similarRoutes.get(i);
            String routeInfo = String.format("相似推荐|路线:%s|终点:%s|使用次数:%d|平均费用:%.2f|平均时长:%.2f|平均距离:%.2f|平均质量:%.1f|热门度:%.3f",
                    route.routeId, route.dropoffLocation, route.usageCount,
                    route.avgAmount, route.avgDuration, route.avgDistance,
                    route.avgQualityScore, route.popularityScore);

            context.write(new Text("相似推荐_" + pickupLocation + "_" + (i + 1)), new Text(routeInfo));
        }
    }

    /**
     * 找出最频繁的项目
     */
    private String findMostFrequent(Map<String, Integer> counts) {
        return counts.entrySet().stream()
                .max(Map.Entry.comparingByValue())
                .map(entry -> entry.getKey() + "(" + entry.getValue() + "次)")
                .orElse("未知");
    }

    /**
     * 解析用户行程数据
     */
    private UserTrip parseUserTrip(String data) {
        try {
            String[] fields = data.split("\\|");
            if (fields.length >= 10) {
                UserTrip trip = new UserTrip();
                trip.routeId = fields[0];
                trip.pickupLocation = fields[1];
                trip.dropoffLocation = fields[2];
                trip.tripDistance = Double.parseDouble(fields[3]);
                trip.totalAmount = Double.parseDouble(fields[4]);
                trip.tripDuration = Double.parseDouble(fields[5]);
                trip.timePeriod = fields[6];
                trip.dayType = fields[7];
                trip.qualityScore = Integer.parseInt(fields[8]);
                trip.qualityLevel = fields[9];
                return trip;
            }
        } catch (Exception e) {
            System.err.println("解析用户行程错误: " + data);
        }
        return null;
    }

    /**
     * 解析路线使用数据
     */
    private RouteUsage parseRouteUsage(String data) {
        try {
            String[] fields = data.split("\\|");
            if (fields.length >= 11) {
                RouteUsage usage = new RouteUsage();
                usage.userId = fields[0];
                usage.pickupLocation = fields[1];
                usage.dropoffLocation = fields[2];
                usage.tripDistance = Double.parseDouble(fields[3]);
                usage.totalAmount = Double.parseDouble(fields[4]);
                usage.tripDuration = Double.parseDouble(fields[5]);
                usage.timePeriod = fields[6];
                usage.dayType = fields[7];
                usage.qualityScore = Integer.parseInt(fields[8]);
                usage.qualityLevel = fields[9];
                usage.tripCount = Integer.parseInt(fields[10]);
                return usage;
            }
        } catch (Exception e) {
            System.err.println("解析路线使用错误: " + data);
        }
        return null;
    }

    /**
     * 解析时间行程数据
     */
    private TimeTrip parseTimeTrip(String data) {
        try {
            String[] fields = data.split("\\|");
            if (fields.length >= 9) {
                TimeTrip trip = new TimeTrip();
                trip.userId = fields[0];
                trip.routeId = fields[1];
                trip.pickupLocation = fields[2];
                trip.dropoffLocation = fields[3];
                trip.tripDistance = Double.parseDouble(fields[4]);
                trip.totalAmount = Double.parseDouble(fields[5]);
                trip.tripDuration = Double.parseDouble(fields[6]);
                trip.qualityScore = Integer.parseInt(fields[7]);
                trip.qualityLevel = fields[8];
                return trip;
            }
        } catch (Exception e) {
            System.err.println("解析时间行程错误: " + data);
        }
        return null;
    }

    /**
     * 解析起点行程数据
     */
    private PickupTrip parsePickupTrip(String data) {
        try {
            String[] fields = data.split("\\|");
            if (fields.length >= 10) {
                PickupTrip trip = new PickupTrip();
                trip.userId = fields[0];
                trip.routeId = fields[1];
                trip.dropoffLocation = fields[2];
                trip.tripDistance = Double.parseDouble(fields[3]);
                trip.totalAmount = Double.parseDouble(fields[4]);
                trip.tripDuration = Double.parseDouble(fields[5]);
                trip.timePeriod = fields[6];
                trip.dayType = fields[7];
                trip.qualityScore = Integer.parseInt(fields[8]);
                trip.qualityLevel = fields[9];
                return trip;
            }
        } catch (Exception e) {
            System.err.println("解析起点行程错误: " + data);
        }
        return null;
    }

    // 内部类定义
    private static class UserTrip {
        String routeId, pickupLocation, dropoffLocation, timePeriod, dayType, qualityLevel;
        double tripDistance, totalAmount, tripDuration;
        int qualityScore;
    }

    private static class RouteUsage {
        String userId, pickupLocation, dropoffLocation, timePeriod, dayType, qualityLevel;
        double tripDistance, totalAmount, tripDuration;
        int qualityScore, tripCount;
    }

    private static class TimeTrip {
        String userId, routeId, pickupLocation, dropoffLocation, qualityLevel;
        double tripDistance, totalAmount, tripDuration;
        int qualityScore;
    }

    private static class PickupTrip {
        String userId, routeId, dropoffLocation, timePeriod, dayType, qualityLevel;
        double tripDistance, totalAmount, tripDuration;
        int qualityScore;
    }

    private static class UserPreference {
        int totalTrips;
        double avgDistance, avgAmount, avgDuration, avgQualityScore;
        String preferredTimePeriod, preferredDayType, preferredQualityLevel;
    }

    private static class RouteRecommendation {
        String routeId, reason;
        double score, avgAmount, avgDuration, avgQualityScore;
        int usageCount;
    }

    private static class RouteCharacteristics {
        int totalUsages, uniqueUsers;
        double avgDistance, avgAmount, avgDuration, avgQualityScore, userDiversity;
        String popularTimePeriod, popularDayType;
    }

    private static class TimePatternAnalysis {
        int totalTrips;
        double avgDistance, avgAmount, avgDuration, avgQualityScore;
        String popularRoute, popularPickup, popularDropoff;
    }

    private static class SimilarRoute {
        String routeId, dropoffLocation;
        int usageCount;
        double avgAmount, avgDuration, avgDistance, avgQualityScore, popularityScore;
    }

    private static class RouteStats {
        int usageCount, totalQualityScore;
        double totalAmount, totalDuration;
    }

    private static class SimilarRouteStats {
        String dropoffLocation;
        int usageCount, totalQualityScore;
        double totalAmount, totalDuration, totalDistance;
    }
}
